Skip to content

feat(agentex-ui): grow chat input vertically for multi-line prompts#332

Open
declan-scale wants to merge 2 commits into
mainfrom
declan-scale/AGX1-386-chat-input-grow-vertically
Open

feat(agentex-ui): grow chat input vertically for multi-line prompts#332
declan-scale wants to merge 2 commits into
mainfrom
declan-scale/AGX1-386-chat-input-grow-vertically

Conversation

@declan-scale

@declan-scale declan-scale commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Problem

The plain-text prompt input in the golden agent UI (agentex-ui/components/primary-content/prompt-input.tsx) is an <input type="text">. Longer messages scroll horizontally inside the single line, so authors of multi-line prompts (lists, code snippets, paragraphs) can't see what they've typed or edit it comfortably before sending. Prompt quality directly affects agent output, so the friction matters.

Fix

Swap the plain-text input for an auto-growing <textarea> in the same component. The JSON / CodeMirror branch already grows vertically up to 200px — use the same cap on the text branch so the two variants feel consistent.

Specifically:

  • Replace <input type="text"> with <textarea rows={1}> in the TextInput subcomponent.
  • Auto-resize on every prompt change: reset to auto, then set height = min(scrollHeight, 200px); toggle overflow-y to auto once the cap is hit so it scrolls internally.
  • Update the outer flex container from items-center to items-end so the size-10 send button stays anchored at the bottom of the row as the textarea grows.
  • Give the textarea py-2 leading-6 so the single-line natural height (8 + 24 + 8 = 40px) matches the send button height — preserves today's container height and the visual centering of short messages.
  • Keep resize-none and cap maxHeight inline so the user can't drag-resize past the cap.
  • Update textInputRef and TextInput's inputRef prop type from HTMLInputElement to HTMLTextAreaElement.

Keyboard behavior

  • Enter sends the message (same as before).
  • Shift+Enter inserts a newline (default textarea behavior; we just don't preventDefault in that case).
  • Enter is also ignored while an IME composition is active (e.nativeEvent.isComposing) so CJK candidate selection isn't hijacked.

The JSON branch continues to use Cmd/Ctrl+Enter (Mod-Enter) to send — that path is unchanged.

Out of scope (matches the issue)

  • Rich-text / markdown rendering in the composer.
  • Drag-to-resize handle.
  • Changes to the JSON / CodeMirror branch.

Validation

Local validation was skipped per agent policy — relying on CI for typecheck/lint/format. The pinned prettier is 3.x; only 2.8 is available on PATH in this environment, so I did not auto-format (mixing prettier majors causes unrelated reformatting). The diff matches the file's existing style.

Reviewer test plan

  • Open the golden agent chat surface; the prompt input renders at the same visual height as before for an empty / single-line message.
  • Type a long message that wraps; the textarea grows vertically as new lines are added, and the rounded container grows with it.
  • Continue typing past ~200px; the textarea stops growing and scrolls internally.
  • The send button stays visible and clickable at every height, anchored to the bottom-right of the row.
  • Enter sends the message; Shift+Enter inserts a newline without sending.
  • Disabled state (no agent selected, or task terminal) still renders with the muted background and cursor-not-allowed.
  • Toggling the "Send JSON" switch still swaps in the CodeMirror editor unchanged.
  • (Optional) Verify CJK IME composition: pressing Enter to commit a candidate does not send the message.

Linear

AGX1-386

Greptile Summary

This PR swaps the single-line <input type="text"> in the TextInput sub-component for an auto-growing <textarea> capped at 200 px, matching the JSON/CodeMirror branch's existing cap. The flex container alignment is updated from items-center to items-end so the send button stays bottom-anchored as the textarea grows, and py-2 leading-6 keeps the single-line height identical to the previous input.

  • Auto-resize effect resets height to 'auto' on each prompt change, reads the natural scrollHeight, clamps it to 200 px, and toggles overflowY accordingly.
  • Keyboard handling calls e.preventDefault() on bare Enter while Shift+Enter inserts a newline; IME composition guard prevents hijacking CJK candidate selection.
  • Ref type is narrowed from HTMLInputElement to HTMLTextAreaElement throughout.

Confidence Score: 5/5

Safe to merge — the change is isolated to a single UI sub-component and handles all stated keyboard edge-cases correctly.

The resize effect, keyboard logic, ref-type update, and flex-alignment change are all self-contained and correct. No state management, API calls, or shared utilities are affected.

No files require special attention.

Important Files Changed

Filename Overview
agentex-ui/components/primary-content/prompt-input.tsx Replaces <input type="text"> with an auto-growing <textarea> capped at 200px; adds IME-aware Enter/Shift+Enter keyboard handling; updates ref type and flex alignment — logic is correct with only a minor style nit in the resize effect.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User types in TextInput textarea] --> B[prompt state updates]
    B --> C[useEffect runs auto-resize logic]
    C --> D[el.style.height = 'auto']
    D --> E[Read el.scrollHeight]
    E --> F{scrollHeight > 200px?}
    F -- No --> G[height = scrollHeight, overflowY = hidden]
    F -- Yes --> H[height = 200px, overflowY = auto]
    A2[User presses key] --> I{Enter, no Shift, no IME?}
    I -- No --> J[Default browser behavior]
    I -- Yes --> K[e.preventDefault]
    K --> L{enabled AND prompt not empty?}
    L -- Yes --> M[handleSendPrompt, clears prompt]
    L -- No --> N[No-op]
    M --> B
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[User types in TextInput textarea] --> B[prompt state updates]
    B --> C[useEffect runs auto-resize logic]
    C --> D[el.style.height = 'auto']
    D --> E[Read el.scrollHeight]
    E --> F{scrollHeight > 200px?}
    F -- No --> G[height = scrollHeight, overflowY = hidden]
    F -- Yes --> H[height = 200px, overflowY = auto]
    A2[User presses key] --> I{Enter, no Shift, no IME?}
    I -- No --> J[Default browser behavior]
    I -- Yes --> K[e.preventDefault]
    K --> L{enabled AND prompt not empty?}
    L -- Yes --> M[handleSendPrompt, clears prompt]
    L -- No --> N[No-op]
    M --> B
Loading

Reviews (2): Last reviewed commit: "style(agentex-ui): collapse Enter keydow..." | Re-trigger Greptile

The plain-text prompt was a single-line input, so long messages scrolled
horizontally and users couldn't review what they had typed. Swap it for a
textarea that auto-grows up to 200px (matching the JSON / CodeMirror cap),
then scrolls internally. Align the surrounding row to items-end so the
send button stays anchored to the bottom as the input grows. Enter sends;
Shift+Enter inserts a newline.

Refs: AGX1-386
@declan-scale declan-scale requested a review from a team as a code owner June 22, 2026 23:30
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants